12.1: Memuat dan menampilkan data yang diambil dari penyedia konten
Daftar Isi:
- Yang harus sudah Anda KETAHUI
- Yang akan Anda PELAJARI
- Yang akan Anda LAKUKAN
- Ringkasan Aplikasi
- Tugas 1. Membuat aplikasi dasar untuk WordListLoader
- Tugas 2: MainActivity: Menambahkan LoaderManager dan LoaderCallbacks
- Tugas 3: WordListAdapter: Implementasikan setData(), getItemCount(), dan onBindViewHolder()
- Rangkuman
- Konsep terkait
Dalam praktik ini Anda akan mempelajari cara memuat data yang disediakan oleh penyedia konten aplikasi lain latar belakang dan menampilkannya kepada pengguna, saat sudah siap.
Meminta ContentProvider untuk menyediakan data yang ingin Anda tampilkan bisa memakan waktu. Jika Anda meminta data dari penyedia konten dari sebuah Aktivitas (dan menjalankannya di thread UI], aplikasi bisa diblokir cukup lama sehingga penundaan cukup terlihat untuk pengguna dan sistem bahkan bisa mengeluarkan pesan "Application Not Responding". Dengan demikian, Anda harus memuat data di thread yang terpisah, latar belakang, dan menampilkan hasilnya setelah pemuatan selesai.
Untuk menjalankan kueri di thread yang terpisah, Anda harus menggunakan loader yang berjalan secara asinkron latar belakang dan menghubungkan ulang ke Aktivitas setelah selesai. Khususnya, CursorLoader menjalankan kueri di latar belakang, dan otomatis menjalankan ulang kueri saat data yang terkait dengan kueri berubah.
Anda telah menggunakan AsyncTaskLoader di praktik sebelumnya. CursorLoader memperluas AsyncTaskLoader untuk bekerja dengan penyedia konten.
Di tingkat tinggi, Anda memerlukan bagian ini untuk menggunakan loader untuk menampilkan data dari penyedia konten:
- Sebuah Aktivitas atau fragmen.
- Sebuah instance LoaderManager di Aktivitas.
- Sebuah CursorLoader untuk memuat data yang didukung oleh ContentProvider.
- Sebuah implementasi untuk LoaderCallbacks.LoaderCallbacks, sebuah antarmuka callback bagi klien untuk berinteraksi dengan LoaderManager.
- Cara untuk menampilkan data loader, umumnya menggunakan sebuah adaptor. Misalnya, Anda bisa menampilkan data di RecyclerView.
Diagram berikut menampilkan arsitektur aplikasi lengkap dengan sebuah loader.
- Loader melakukan kueri untuk item di latar belakang. Jika data berubah, loader otomatis mendapatkan serangkaian data baru untuk adaptor.
- Operasi penyisipan, penghapusan, dan pembaruan tidak menggunakan loader. Akan tetapi, setelah data berubah karena operasi penyisipan, penghapusan, atau pembaruan, loader mengambil data yang diperbarui dan memberi tahu adaptor.
Yang harus sudah Anda KETAHUI
Untuk praktik ini Anda harus bisa:
- Menampilkan data di RecyclerView.
- Bekerja dengan Adaptor sederhana.
- Memahami Kursor (lihat praktik dan konsep sebelumnya.)
- Bekerja dengan AsyncTaskLoader.
- Memahami cara bekerja dengan Penyedia Konten.
Yang akan Anda PELAJARI
Anda akan belajar:
- Memuat data dari penyedia konten menggunakan CursorLoader.
- Menggunakan kode dari aplikasi yang telah selesai untuk membangun aplikasi secara cepat dengan fungsionalitas terkait.
Yang akan Anda LAKUKAN
- Anda akan membuat aplikasi dasar yang menggunakan CursorLoader untuk melakukan kueri pada penyedia konten WordListSQLWithContentProvider dan menampilkan data di RecyclerView.
- Gunakan WordListClient sebagai referensi untuk beberapa kode. Khususnya, Anda bisa menggunakan Kelas Contract dan WordItem, serta bagian dari kelas MainActivity dan WordListAdapter.
- Aplikasi yang akan Anda buat akan memiliki UI yang sangat dasar. Tidak seperti WordListClient, ini tidak akan memiliki fungsionalitas penyisipan, penghapusan, atau pembaruan.
Ringkasan Aplikasi
Menggunakan WordListClient dari praktik sebelumnya sebagai sumber untuk beberapa kode, Anda akan membuat aplikasi baru, WordListLoader yang memuat dan menampilkan data dari penyedia konten untuk WordListSQLWithContentProvider. Tangkapan layar berikut menampilkan bagaimana aplikasi yang telah selesai akan menampilkan kata.
- Anda harus memasang aplikasi WordListWithContentProvider yang membagikan penyedia kontennya sehingga tersedia penyedia konten untuk WordListLoader.
- Gunakan aplikasi WordListClient yang telah Anda bangun di praktik sebelumnya sebagai referensi dan untuk menggunakan ulang kode.
Tugas 1. Membuat aplikasi dasar untuk WordListLoader
Dalam tugas ini, Anda akan memuat proyek dan bagian aplikasi yang tidak spesifik untuk loader. Anda harus memuat aplikasi WordListClient di Android Studio, sehingga Anda bisa menyalin kode darinya.
1.1 Buat proyek dengan kelas Contract dan WordListItem dan file layout.
- Mulailah Android Studio dan muat aplikasi WordListClient yang sudah selesai dari praktik sebelumnya.
- Buat proyek baru dengan template Empty Activity dan beri nama WordListLoader.
- Tambahkan izin untuk penyedia konten WordListSQLWithContentProvider ke Manifes Android.
<uses-permission android:name = "com.android.example.wordlistsqlwithcontentprovider.PERMISSION"/>
- Buat kelas Java baru dan beri nama Contract.
- Salin kelas Contract dari WordListClient ke kelas Contract baru WordListLoader. Pastikan Anda tidak menyalin nama paket.
- Di WordListLoader, buat kelas Java baru dan beri nama WordListItem.
- Salin kelas WordItem dari WordListClient ke kelas WordItem baru WordListLoader.
- Salin layout tampilan recycler dari activity_main.xml dari WordListClient ke WordListLoader. Buang tombol aksi mengambang.
- Buat layout baru untuk WordListItem, wordlist_item.xml.
- Menggunakan wordlist_item.xml dari WordListClient sebagai referensi Anda, buat LinearLayout dengan satu TextView.
- Id TextView harus
android:id="@+id/word".
- Selesaikan string, dimensi, dan gaya dan Anda gunakan kembali. Perhatikan bahwa Anda bisa menyalin/menempel antar proyek. Ganti file XML yang sudah ada di WordListLoader.
- Ubah app_name ke WordListLoader di strings.xml.
- Id TextView harus
- Di tahap ini, Anda seharusnya tidak melihat kesalahan di Android Studio.
1.2 Tambahkan sebuah RecyclerView ke MainActivity
Untuk menampilkan data, tambahkan RecyclerView ke MainActivity. Anda bisa melakukan ini sendiri atau menggunakan kembali kode dari WordListClient.
- Tambahkan RecyclerView dan Layout Coordinator dari pustaka dukungan ke file build.gradle Anda.
compile 'com.android.support:recyclerview-v7:24.1.1' compile 'com.android.support:design:24.1.1'
- Impor versi pustaka dukungan RecyclerView dan LinearLayoutManager ke MainActivity Anda.
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView;
- Buat TAG untuk MainActivity.
- Buat variabel pribadi mRecyclerView untuk RecyclerView.
- Buat variabel pribadi mWordListAdapter untuk adaptor. Ini akan tetap berwarna merah, sampai Anda membuat kelas adaptor.
- Di onCreate() MainActivity, buat RecyclerView, buat WordListAdapter, setel adaptor di RecyclerView, dan lampirkan sebuah LinearLayoutManager. Lihat WordListClient untuk kode contoh.
// Create recycler view. mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview); // Create an adapter and supply the data to be displayed. mAdapter = new WordListAdapter(this); // Connect the adapter with the recycler view. mRecyclerView.setAdapter(mAdapter); // Give the recycler view a default layout manager. mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- Jika Anda membangun aplikasi Anda sekarang, hanya WordListAdapter yang berwarna merah. Aplikasi belum berjalan.
1.3 Buat WordListAdapter
Gunakan WordListAdapter dari WordListClient dan cuplikan berikut sebagai referensi untuk membuat adaptor ini. Jika memerlukan informasi pengingat, baca lagi bab RecyclerView di kursus ini.
Buat kelas Java baru WordListAdapter yang memperluas RecyclerView.Adapter.
public class WordListAdapter extends RecyclerView.Adapter<WordListAdapter.WordViewHolder> {}
Menggunakan WordListAdapter sebagai referensi, tambahkan yang berikut ini:
Tambahkan kelas ViewHolder dalam dengan satu TextView, yang bernama wordItemView dan mekarkan dari tampilan teks dengan id "word".
class WordViewHolder extends RecyclerView.ViewHolder { public final TextView wordItemView; public WordViewHolder(View itemView) { super(itemView); wordItemView = (TextView) itemView.findViewById(word); } }
- Tambahkan TAG untuk pesan log.
private static final String TAG = WordListAdapter.class.getSimpleName();
- Tambahkan variabel anggota untuk LayoutInflator dan konteks.
private final LayoutInflater mInflater; private Context mContext;
- Implementasikan constructor untuk WordListAdapter.
public WordListAdapter(Context context) { mInflater = LayoutInflater.from(context); this.mContext = context; }
- Implementasikan (atau salin) metode onCreateViewHolder untuk memekarkan tampilan wordlist_item.
@Override public WordViewHolder onCreateViewHolder( ViewGroup parent, int viewType) { View mItemView = mInflater.inflate( R.layout.wordlist_item, parent, false); return new WordViewHolder(mItemView); }
- Tekan Alt-Enter pada header kelas adaptor dan "choose implement methods" untuk membuat stub metode untuk metode
getItemCount()
danonBindViewHolder()
. - Pada tahap ini, seharusnya sudah tidak ada lagi garis bawah merah atau kata di kode Anda.
- Jalankan aplikasi Anda yang seharusnya akan menampilkan aktivitas kosong seperti yang ditampilkan di tangkapan layar berikut, karena Anda belum memuat data apa pun. Anda akan menambahkan data di tugas berikutnya.
Tugas 2. MainActivity: Menambahkan LoaderManager dan LoaderCallbacks
Ketika Anda menggunakan sebuah loader untuk memuat data, gunakan pengelola loader untuk menangani detail berjalannya loader.
LoaderManager adalah kelas bantu yang mengelola semua loader Anda. Anda hanya perlu satu pengelola loader per aktivitas. Misalnya, pengelola loader menangani pendaftaran sebuah observer dengan penyedia konten, yang menerima callback ketika data di penyedia konten berubah.
2.1 Tambahkan Pengelola Loader
- Buka MainActivity.java
- Perluas tanda tangan kelas untuk mengimplementasikan LoaderManager.LoaderCallbacks
. Impor versi pustaka dukungan. public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>
- Implementasikan stub metode untuk
onCreateLoader()
,onLoadFinished()
, danonLoaderReset()
. - Di onCreate(), buat LoaderManager dari pustaka dukungan dan daftarkan sebuah loader dengannya.
- Argumen pertama adalah tag numerik; karena Anda hanya memiliki satu loader, nomor yang Anda pilih tidaklah penting.
- Anda tidak meneruskan data apa pun, sehingga argumen kedua adalah null.
- Dan Anda melekatkan loader ke MainActivity(this) saat ini.
getSupportLoaderManager().initLoader(0, null, this);
2.2. Implementasikan onCreateLoader()
LoaderManager memanggil metode onCreateLoader() untuk membuat loader, jika belum ada.
Anda membuat loader dengan memberikannya konteks dan URI asal data dimuat—dalam hal ini, untuk penyedia konten WordListSQLWithContentProvider, URI yang ditetapkan di Contract.
- Di onCreateLoader(), buat sebuah queryUri dan projection. Gunakan URI yang sama dengan yang digunakan oleh resolver konten untuk melakukan kueri pada penyedia konten. Anda bisa menemukan ini di Contract dan ini digunakan di WordListClient.
- Buat dan kembalikan CursorLoader baru dari argumen ini. Impor CursorLoader dari pustaka dukungan.
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String queryUri = Contract.CONTENT_URI.toString(); String[] projection = new String[] {Contract.CONTENT_PATH}; return new CursorLoader(this, Uri.parse(queryUri), projection, null, null, null); }
2.3 Implementasikan onLoadFinished()
Setelah pemuatan selesai, Anda perlu mengirimkan data ke adaptor.
- Panggil setData() di onLoadFinished(). Kode akan berubah menjadi merah, dan Anda akan mengimplementasikannya di tugas berikutnya. Argumen untuk setData() adalah kursor dengan "data" yang dikembalikan oleh loader setelah selesai dimuat.
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { mAdapter.setData(data); }
2.4 Implementasikan onLoaderReset()
Saat menyetel ulang loader, beri tahu adaptor bahwa data sudah tidak tersedia dengan meneruskan null ke setData().
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.setData(null);
}
Tugas 3: WordListAdapter: Mengimplementasikan setData(), getItemCount(), dan onBindViewHolder()
Sebagai tugas akhir, Anda perlu mengimplementasikan metode setData() yang direferensikan di atas, dan mengimplementasikan onBindViewHolder() untuk bekerja dengan loader untuk menampilkan data. Berikut ini prosesnya:
- Saat loader selesai memuat data baru atau yang diubah latar belakang, metode onLoadFinished() yang Anda implementasikan di MainActivity dieksekusi.
- onLoadFinished() memanggil WordListAdapter.setData(), yang memperbarui variabel mCursor di adaptor dengan data terakhir loader dan memberi tahu adaptor bahwa data telah diubah.
- Adaptor memperbarui UI dengan data baru, dengan melekatkan tampilan ke data di onBindViewHolder().
3.1 Implementasikan setData()
Anda memerlukan cara untuk menyetel dan menyimpan versi data yang terakhir dimuat dengan adaptor. Untuk aplikasi ini, loader mengembalikan data sebagai kursor, sehingga Anda perlu membuat variabel anggota Cursor mCursor yang akan selalu menampung rangkaian data terakhir.
Metode setData() dipanggil oleh loader ketika selesai dimuat atau disetel ulang, dan perlu memperbarui mCursor.
- Buat variabel anggota pribadi tipe Cursor. Beri nama "mCursor" dan inisialisasi ke null.
- Implementasikan metode publik setData(). Ini mengambil argumen Cursor dan tidak mengembalikan apa pun.
- Di isi, setel mCursor ke argumen Cursor yang diteruskan dan panggil notifyDataSetChanged(), sehingga adaptor memperbarui tampilan.
public void setData(Cursor cursor) { mCursor = cursor; notifyDataSetChanged(); }
3.2. Implementasikan getItemCount()
Sebagai ganti 0, getItemCount() perlu mengembalikan jumlah item di mCursor. Jika mCursor null, kembalikan -1.
@Override
public int getItemCount() {
if (mCursor != null) {
return mCursor.getCount();
} else {
return -1;
}
}
3.3. Implementasikan onBindViewHolder()
Di WordListClient, metode onBindViewHolder() menggunakan resolver konten untuk mengambil data dari penyedia konten WordListSQLWithContentProvider. Di aplikasi ini, onBindViewHolder() menggunakan data yang disediakan loader dan menyimpannya di mCursor.
Di onBindViewHolder, tangani situasi berikut.
- Jika mCursor null, jangan lakukan apa pun, kecuali menampilkan pesan log. Di aplikasi nyata, Anda juga perlu memberi tahu pengguna dengan cara yang mudah dipahami.
- Jika mCursor tidak null tetapi tidak berisi kata, setel teks di TextView ke ERROR: NO WORD. Sekali lagi, di aplikasi nyata, Anda akan menangani ini bergantung pada tipe aplikasi yang Anda miliki.
Jika tidak, dapatkan indeks kolom untuk kolom "word" (Anda tidak bisa mengasumsikan kolom berada di lokasi tetap di baris kursor) dan menggunakan indeks, mengambil kata Setel teks di tampilan teks ke kata.
@Override public void onBindViewHolder(WordViewHolder holder, int position) { String word = ""; if (mCursor != null) { if (mCursor.moveToPosition(position)) { int indexWord = mCursor.getColumnIndex(Contract.WordList.KEY_WORD); word = mCursor.getString(indexWord); holder.wordItemView.setText(word); } else { holder.wordItemView.setText(R.string.error_no_word); } } else { Log.e (TAG, "onBindViewHolder: Cursor is null."); } }
3.4 Jalankan dan uji aplikasi Anda
Aplikasi WordListLoader Anda harus bekerja sama persis dengan aplikasi WordListClient untuk menampilkan daftar kata. Untuk menguji aplikasi Anda, lakukan yang berikut.
- Pastikan WordListSQLWithContentProvider dipasang di perangkat, sehingga aplikasi Anda memiliki penyedia konten yang menjadi sumber pemuatan. Jika tidak, aplikasi Anda akan menampilkan tampilan teks kosong.
- Jalankan WordListLoader. Anda akan melihat daftar kata yang sama seperti di WordListSQLWithContentProvider.
Kode solusi
Proyek Android Studio: WordListLoader
Rangkuman
- Di bab ini, Anda telah belajar cara menggunakan loader untuk memuat data dari penyedia konten yang bukan bagian dari aplikasi Anda.
Konsep terkait
Dokumentasi konsep terkait ada di Dasar-Dasar Developer Android: Konsep.